package com.veo.web.servlet;

import com.alibaba.fastjson.JSONObject;
import com.jspsmart.upload.SmartUpload;
import com.jspsmart.upload.SmartUploadException;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

@WebServlet("/fileUploadAndDownServlet")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //文件下载
        String fileName = request.getParameter("fileName");
        String realPath = request.getServletContext().getRealPath("/uploads");

        File fileByName = findFileByName(fileName, new File(realPath));
        System.out.println(fileByName.getName());
        System.out.println(fileName);

        InputStream in = new FileInputStream(fileByName);
        ServletOutputStream out = response.getOutputStream();
        //要对文件名进行转换否则中文显示乱码
        byte[] fileNameBytes = fileName.getBytes(StandardCharsets.UTF_8);
        String transformName = new String(fileNameBytes, StandardCharsets.ISO_8859_1);
        //设置响应头信息为一个文件下载
        response.setHeader("Content-Disposition","attachment;filename=" + transformName);

        byte[] bs = new byte[(int)fileByName.length()];
        in.read(bs);
        out.write(bs);

        out.close();
        in.close();
    }


    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        fileUploadMethod3(request,response);

        String realPath = request.getServletContext().getRealPath("/uploads");
        File file = new File(realPath);
        List<File> allFile = findAllFile(file);
        System.out.println("all:"+allFile.size());

//        request.setAttribute("fs",allFile);
        request.getSession().setAttribute("fs",allFile);
//        request.getRequestDispatcher("/fileDown.jsp").forward(request,response);
        String ok = JSONObject.toJSONString("ok");
        response.getWriter().write(ok);
    }


//    根据文件名找文件，递归查找
    public File findFileByName(String fileName, File file){
        File[] files = file.listFiles();
        File findFile = new File("");
        for (File item : files) {
            if (item.isDirectory()){
                findFile = findFileByName(fileName,item);
            }else {
                if (item.getName().equals(fileName)){
                    findFile = item;
                }
            }
        }
        return findFile;
    }

    public List<File> findAllFile(File file){
        File[] files = file.listFiles();
        ArrayList<File> list = new ArrayList<>();
        for (File item : files) {
            if (item.isDirectory()){
                System.out.println(item.getName());
                list = (ArrayList<File>) findAllFile(item);
            }else {
                System.out.println(item.getName());
                list.add(item);
            }
        }
        return list;
    }

    public void fileUploadMethod1(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        String realPath = request.getServletContext().getRealPath("/uploads");
        //当表单为enctype="multipart/form-data"，时获取到普通表单数据为null, 要加MultipartConfig,才可以获取
        String name = request.getParameter("name");

        //获取文件上传的文件名和格式类型
        String header = request.getPart("uploadFile").getHeader("Content-Disposition");
        //获取原始文件的名字和文件类型
        String uploadFileName = header.substring(header.indexOf("filename=\"") + 10,header.lastIndexOf("\""));
        String extendName = uploadFileName.substring(uploadFileName.indexOf("."));

//        //上传的文件路径
//        String fileName = null;
//        //拼接uuid，防止文件重名
//        String uuid = UUID.randomUUID().toString().replace("-","").toUpperCase();
//        //拼接日期给文件上传按日期分类
//        String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
//
//        if (name != null && !"".equals(name)){
//            fileName = uuid + "-" + name + extendName;
//        }else {
//            fileName = uuid + "-" + uploadFileName;
//        }
//
//        File file = new File(realPath, datePath);
//        if (!file.exists()){
//            //当前文件日期不存在就新建一个目录
//            file.mkdirs();
//        }
//        File filePath = new File(file, fileName);

        File filePath = makeFileName(realPath,name,uploadFileName,extendName);


        System.out.println("表单输入值为：" + name + "文件名："+uploadFileName+" ，后缀为："+extendName + "文件上传路径为：" + filePath.getAbsolutePath());


        InputStream in = request.getPart("uploadFile").getInputStream();
        OutputStream out = new FileOutputStream(filePath);
        int len = -1;
        byte[] bytes = new byte[1024];
        while ((len = in.read(bytes)) != -1){
            out.write(bytes,0,len);
        }

        out.close();
        in.close();
    }


    public void fileUploadMethod2(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, FileUploadException {
        request.setCharacterEncoding("utf-8");
        //判断是否为一个文件上传表单
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (!isMultipart){
            throw new RuntimeException("表单类型不正确");
        }
        //创建文件上传的磁盘工厂，设置文件上传的地址
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setRepository(new File(request.getServletContext().getRealPath("/uploads")));
        String realPath = request.getServletContext().getRealPath("/uploads");
        ServletFileUpload upload = new ServletFileUpload(factory);
        //设置编码格式
        upload.setHeaderEncoding("utf-8");
        //还可设置文件大小等参数

        //获取文件上传的信息
        Map<String, List<FileItem>> map = upload.parseParameterMap(request);
        Iterator<Map.Entry<String, List<FileItem>>> iterator = map.entrySet().iterator();
        String name = "";
        while (iterator.hasNext()){
            Map.Entry<String, List<FileItem>> entry = iterator.next();
//            System.out.println("kay：" + entry.getKey() + "value：" + entry.getValue());
            List<FileItem> value = entry.getValue();
            for (FileItem fileItem : value) {
                //判断是否为普通的表单元素
                if (fileItem.isFormField()){
                    name = fileItem.getString("utf-8");
                    System.out.println("普通表单名为：" + fileItem.getFieldName() + "，值为：" + fileItem.getString("utf-8"));
                    //以下为文件
                }else {
                    String uploadFileName = fileItem.getName();
                    System.out.println("文件原始名为：" + uploadFileName);
                    String extendName = uploadFileName.substring(uploadFileName.indexOf("."));
                    File file = makeFileName(realPath,name,uploadFileName,extendName);
                    try {
                        fileItem.write(file);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public void fileUploadMethod3(HttpServletRequest request, HttpServletResponse response){
        String realPath = request.getServletContext().getRealPath("/uploads");
        SmartUpload upload = new SmartUpload();
        try {
            upload.initialize(this.getServletConfig(),request,response);
            upload.setCharset("utf-8");
            upload.upload();
            //设置允许上传的参数
//            upload.setAllowedFilesList("txt,doc,xml,jpg,docx");
            //直接使用request 是获取不到普通表单的数据的，要使用SmartUpload的request 来获取
            String name = upload.getRequest().getParameter("name");
            String uploadFileName = upload.getFiles().getFile(0).getFileName();
            String extendName = uploadFileName.substring(uploadFileName.indexOf("."));
            System.out.println("普通表单的值：" + name + "，文件原始名称为：" + uploadFileName);

            com.jspsmart.upload.File file = upload.getFiles().getFile(0);

            File filePath = makeFileName(realPath, name, uploadFileName, extendName);
            String fileName = filePath.getPath().substring(filePath.getPath().lastIndexOf("\\") + 1);
            String fileParentPath = filePath.getPath().substring(0,filePath.getPath().lastIndexOf("\\"));
            System.out.println(filePath.getPath());
            System.out.println(fileParentPath);
            System.out.println(fileName);

            file.saveAs(fileParentPath + "/" + fileName);

            //指定文件名保存
//            file.saveAs(file.getAbsolutePath(),filename);
//
//            upload.save(file.getAbsolutePath());

        } catch (SmartUploadException | IOException | ServletException e) {
            e.printStackTrace();
        }

    }

    /**
     * 创建返回的文件，并以时间分类
     * @param realPath 上传文件服务器路径
     * @param name 用户输入文件名
     * @param uploadFileName 上传文件的原始名称
     * @param extendName 文件扩展名
     * @return File
     */
    public File makeFileName(String realPath, String name, String uploadFileName, String extendName){
        //拼接uuid，防止文件重名
        String uuid = UUID.randomUUID().toString().replace("-","").toUpperCase();
        //拼接日期给文件上传按日期分类
        String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String fileName = null;

        if (name != null && !"".equals(name)){
            fileName = uuid + "-" + name + extendName;
        }else {
            fileName = uuid + "-" + uploadFileName;
        }

        File file = new File(realPath, datePath);
        if (!file.exists()){
            //当前文件日期不存在就新建一个目录
            file.mkdirs();
        }
        return new File(file, fileName);
    }
}
